#include <iostream>
#include <memory>
#include <mutex>
#include <thread>

// 1.局部静态变量 - 多线程不安全
class Single_static {
   private:
    Single_static() {}
    Single_static(const Single_static&) = delete;
    Single_static& operator=(const Single_static&) = delete;

   public:
    static Single_static& GetInit() {
        static Single_static _single_static;
        return _single_static;
    }
};

// 2.饿汉式初始化 - 难从规则上设置单例
class Single_hungry {
   private:
    Single_hungry() {}
    Single_hungry(const Single_hungry&) = delete;
    Single_hungry& operator=(const Single_hungry&) = delete;

   public:
    static Single_hungry* GetInit() {
        if (single == nullptr) {
            single = new Single_hungry();
        }
        return single;
    }

   private:
    static Single_hungry* single;
};

Single_hungry* Single_hungry::single = Single_hungry::GetInit();

void threadfunc_Single_static(int i) {
    std::cout << "this is thread " << i << std::endl;
    std::cout << "inst is " << Single_hungry::GetInit() << std::endl;
}

void Test_Single_static() {
    std::cout << "s1 addr is " << Single_hungry::GetInit() << std::endl;
    std::cout << "s2 addr is " << Single_hungry::GetInit() << std::endl;
    for (int i = 0; i < 2; i++) {
        std::thread tid(threadfunc_Single_static, i);
        tid.join();
    }
}

// 3.懒汉式初始化
// 多线程难回收指针内容(子线程里初始化,被哪个线程初始化的不知道,并且不走析构函数)
class Single_pointer {
   private:
    Single_pointer() {}
    Single_pointer(const Single_pointer&) = delete;
    Single_pointer& operator=(const Single_pointer&) = delete;

   public:
    ~Single_pointer() { std::cout << "~Single_pointer()" << std::endl; }
    static Single_pointer* GetInit() {
        if (single != nullptr) return single;

        mtx.lock();
        if (single == nullptr) {
            single = new Single_pointer();
        }
        mtx.unlock();
        return single;
    }

   private:
    static Single_pointer* single;
    static std::mutex mtx;
};

Single_pointer* Single_pointer::single = nullptr;
std::mutex Single_pointer::mtx;

void threadfunc_Single_pointer(int i) {
    std::cout << "this is thread " << i << std::endl;
    std::cout << "inst is " << Single_pointer::GetInit() << std::endl;
}

void Test_Single_pointer() {
    std::cout << "inst is " << Single_pointer::GetInit() << std::endl;
    for (int i = 0; i < 2; i++) {
        std::thread tid(threadfunc_Single_pointer, i);
        tid.join();
    }
}

// 4.智能指针模式
class Single_share {
   private:
    Single_share() {}
    Single_share(const Single_share&) = delete;
    Single_share& operator=(const Single_share&) = delete;

   public:
    // 确实会走析构函数
    ~Single_share() { std::cout << "~Single_share()" << std::endl; }
    static std::shared_ptr<Single_share> GetInit() {
        if (single != nullptr) return single;

        mtx.lock();
        if (single == nullptr) {
            single = std::shared_ptr<Single_share>(new Single_share);
        }
        mtx.unlock();
        return single;
    }

   private:
    static std::shared_ptr<Single_share> single;
    static std::mutex mtx;
};

std::shared_ptr<Single_share> Single_share::single = nullptr;
std::mutex Single_share::mtx;

void threadfunc_Single_share(int i) {
    std::cout << "this is thread " << i << std::endl;
    std::cout << Single_share::GetInit() << std::endl;
}

void Test_Single_share1() {
    std::cout << "inst is " << Single_share::GetInit() << std::endl;
    for (int i = 0; i < 2; i++) {
        std::thread tid(threadfunc_Single_share, i);
        tid.join();
    }
}

void Test_Single_share2() {
    auto t1 = Single_share::GetInit();
    auto t2 = Single_share::GetInit();
    std::cout << t1 << std::endl;
    std::cout << t2 << std::endl;
    // 手动释放会出现重复释放问题
    // delete t1.get();
}

// 5.智能指针的析构设置为私有
// 无法手动释放
class Single_share_safe;

class Safe_delete {
   public:
    void operator()(Single_share_safe* sf) {
        std::cout << "Safe_delete to delete Single_share_safe's pointer"
                  << std::endl;
        delete sf;
    }
};

class Single_share_safe {
   private:
    Single_share_safe() {}
    Single_share_safe(const Single_share_safe&) = delete;
    Single_share_safe& operator=(const Single_share_safe&) = delete;
    ~Single_share_safe() {}

    // 定义友元类，通过友元类调用该类析构函数
    friend class Safe_delete;

   public:
    static std::shared_ptr<Single_share_safe> GetInit() {
        if (single != nullptr) return single;

        mtx.lock();
        if (single == nullptr) {
            single = std::shared_ptr<Single_share_safe>(new Single_share_safe,
                                                        Safe_delete());
        }
        mtx.unlock();
        return single;
    }

   private:
    static std::shared_ptr<Single_share_safe> single;
    static std::mutex mtx;
};

std::shared_ptr<Single_share_safe> Single_share_safe::single = nullptr;
std::mutex Single_share_safe::mtx;

void Test_Single_share_safe() {
    auto t1 = Single_share_safe::GetInit();
    auto t2 = Single_share_safe::GetInit();
    std::cout << t1 << std::endl;
    std::cout << t2 << std::endl;

    // 原先这样写不会在编译的时候提示报错,只会在执行之后发现出现多次析构的现象
    // 现在的情况是由于析构函数是private所以编译的时候就出现错误
    // delete t1;
}

// 6.call_once函数实现
class SingleOnce {
   private:
    SingleOnce() {}
    SingleOnce(const SingleOnce&) = delete;
    SingleOnce& operator()(const SingleOnce&) = delete;

   public:
    ~SingleOnce() { std::cout << "~SingleOnce()" << std::endl; }
    void PrintAddress() { std::cout << single.get() << std::endl; }
    static std::shared_ptr<SingleOnce> GetInit() {
        static std::once_flag s_flag;
        std::call_once(s_flag, [&]() {
            single = std::shared_ptr<SingleOnce>(new SingleOnce);
        });
        return single;
    }

   private:
    static std::shared_ptr<SingleOnce> single;
};
std::shared_ptr<SingleOnce> SingleOnce::single = nullptr;

void TestSingle() {
    std::thread t1([]() {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        SingleOnce::GetInit()->PrintAddress();
    });
    std::thread t2([]() {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        SingleOnce::GetInit()->PrintAddress();
    });
    t1.join();
    t2.join();
}

// 7.单例模式的继承关系设计
template <class T>
class Singleton {
   protected:
    Singleton() {}
    Singleton(const Singleton<T>&) = delete;
    Singleton& operator=(const Singleton<T>&) = delete;
    static std::shared_ptr<T> single;

   public:
    static std::shared_ptr<T> GetInit() {
        static std::once_flag of;
        std::call_once(of, [&]() { single = std::shared_ptr<T>(new T); });
        return single;
    }
};
template <class T>
std::shared_ptr<T> Singleton<T>::single = nullptr;

class LogicSystem : public Singleton<LogicSystem> {
    friend class Singleton<LogicSystem>;

   public:
    ~LogicSystem() {}

   private:
    LogicSystem() {}
};

void TestSingleton() {
    std::thread t1([]() { std::cout << LogicSystem::GetInit() << std::endl; });
    std::thread t2([]() { std::cout << LogicSystem::GetInit() << std::endl; });
    t1.join();
    t2.join();
}

int main() {
    // Test_Single_static();
    // Test_Single_pointer();
    // Test_Single_share1();
    // Test_Single_share2();
    // Test_Single_share_safe();
    // TestSingle();
    // TestSingleton();
    return 0;
}